<script setup lang="ts">
import { computed, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import type { FormInst, FormItemInst } from 'naive-ui';
import { useMessage, NButton, NCard, NForm, NFormItem, NInput } from 'naive-ui';
import { updatePassword } from '../api/user';
import statusCode from '../api/statusCode';
import { getToken, removeToken } from '../util/token';
import { handleNoToken, listAllError } from '../util/handler';

const router = useRouter();

const formRef = ref<FormInst | null>(null);
const newPasswordFormItemRef = ref<FormItemInst | null>(null);
const message = useMessage();

const formValue = reactive({
  originalPassword: '',
  newPassword: ''
});

const validatePasswordPattern = (_: unknown, value: string) =>
        /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$/.test(value);

const matchesPasswordPattern = computed(() => validatePasswordPattern(undefined, formValue.originalPassword));

const rules = {
  originalPassword: [
    {
      required: true,
      message: '请输入原密码',
      trigger: 'input'
    },
    {
      validator: validatePasswordPattern,
      message: '密码必须只包含字母和数字，且在6~18位之间',
      trigger: 'input'
    }
  ],
  newPassword: [
    {
      required: true,
      message: '请输入新密码',
      trigger: 'input'
    },
    {
      validator: validatePasswordPattern,
      message: '密码必须只包含字母和数字，且在6~18位之间',
      trigger: ['input', 'n-password-input']
    },
    {
      validator: () => !(formValue.originalPassword === formValue.newPassword),
      message: '原密码不能与旧密码相同',
      trigger: ['input', 'o-password-input', 'n-password-input']
    }
  ]
};

const newPasswordIsValid = ref(false);

const handleOPasswordInput = () => {
  if (formValue.originalPassword) {
    newPasswordFormItemRef.value?.validate({ trigger: 'o-password-input' })
      .then(() => newPasswordIsValid.value = true)
      .catch(() => newPasswordIsValid.value = false);
  }
};

const handleNPasswordInput = () => {
  if (formValue.originalPassword) {
    newPasswordFormItemRef.value?.validate({ trigger: 'n-password-input' })
      .then(() => newPasswordIsValid.value = true)
      .catch(() => newPasswordIsValid.value = false);
  }
};

const formValidate = () => {
  return formRef.value?.validate();
};

const handleButtonClick = async () => {
  try {
    await formValidate();

    const token = getToken();
    if (!token) {
      handleNoToken(message);
      return;
    }

    try {
      const resp = await updatePassword({ ...formValue, token: token });

      if (resp.status === statusCode.SUCCESS) {
        message.success('修改成功，请重新登录', {
          duration: 1500,
          onAfterLeave: () => {
            removeToken();
            router.push({ name: 'login' });
          }
        });
      } else {
        throw new Error(`错误码 ${resp.status}`);
      }
    } catch (error) {
      message.error("" + error);
    }

  } catch (errors) {
    if (errors instanceof Array) {
      listAllError(errors, message);
    } else {
      throw errors;
    }
  }
};
</script>

<template>
  <n-card title="修改密码">
    <n-form
      :model="formValue"
      :rules="rules"
      :show-require-mark="false"
      ref="formRef"
    >
      <n-form-item
        label="原密码"
        path="originalPassword"
      >
        <n-input
          type="password"
          v-model:value="formValue.originalPassword"
          placeholder="原密码"
          :maxlength="16"
          @input="handleOPasswordInput"
        />
      </n-form-item>
      <n-form-item
        label="新密码"
        path="newPassword"
        ref="newPasswordFormItemRef"
      >
        <n-input
          :disabled="!matchesPasswordPattern"
          type="password"
          v-model:value="formValue.newPassword"
          placeholder="新密码"
          :maxlength="16"
          @input="handleNPasswordInput"
        />
      </n-form-item>
      <n-form-item>
        <n-button
          :disabled="!newPasswordIsValid"
          @click="handleButtonClick"
          type="primary"
          attr-type="submit"
        >
          更改
        </n-button>
      </n-form-item>
    </n-form>
  </n-card>
</template>

<style scoped>
</style>
